#include "helper.h"
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <limits>
#include <cstdio>

using namespace std;

vector<string> split(string str, string pattern)
{
    string::size_type pos;
    vector<string> result;
    str += pattern; //扩展字符串以方便操作
    int size = str.size();

    for (int i = 0; i < size; i++)
    {
        pos = str.find(pattern, i);
        if (pos < (uint)size)
        {
            string s = str.substr(i, pos - i);
            result.push_back(s);
            i = pos + pattern.size() - 1;
        }
    }
    return result;
}

string doubleToString(double value, int precisionAfterPoint)
{
    return to_string(value);
}

void print_zval_type(zval *value)
{
    php_printf("mem addr: %ld\n", reinterpret_cast<long>(value));
    switch (Z_TYPE_P(value))
    {
    case IS_TRUE:
        php_printf("print type: bool\n");
        break;
    case IS_FALSE:
        php_printf("print type: bool\n");
        break;
    case IS_STRING:
        php_printf("print type: string\n");
        break;
    case IS_LONG:
        php_printf("print type: long\n");
        break;
    case IS_DOUBLE:
        php_printf("print type: double\n");
        break;
    case IS_ARRAY:
        php_printf("print type: array\n");
        break;
    case IS_OBJECT:
        php_printf("print type: object\n");
        break;
    case IS_RESOURCE:
        php_printf("print type: resource\n");
        break;
    case IS_REFERENCE:
        php_printf("print type: reference\n");
        break;
    case IS_CALLABLE:
        php_printf("print type: callable\n");
        break;
    // case IS_CONSTANT:
    //     php_printf("print type: constant\n");
    //     break;
    case IS_CONSTANT_AST:
        php_printf("print type: constant ast\n");
        break;
    case IS_ITERABLE:
        php_printf("print type: iterable\n");
        break;
    case IS_VOID:
        php_printf("print type: iterable\n");
        break;
    case IS_INDIRECT:
        php_printf("print type: indirect\n");
        break;
    case IS_PTR:
        php_printf("print type: ptr\n");
        break;
    default:
        php_printf("print type: unknown\n");
        break;
    }
}

zval *push_read_property(zval *obj, const char *property)
{
    if (Z_TYPE_P(obj) == IS_OBJECT)
    {
        zend_object *object = obj->value.obj;
        zend_class_entry *ce;

        ce = object->ce;

        return zend_read_property(ce, obj, property, strlen(property), 0, nullptr);
    }
    return nullptr;
}

zval *read_obj_property(zval *obj, const char *property, string obj_class)
{
    if (Z_TYPE_P(obj) == IS_OBJECT)
    {
        zend_object *object = obj->value.obj;
        zend_class_entry *ce;

        ce = object->ce;

        zval *res = zend_read_property(ce, obj, property, strlen(property), 0, nullptr);
        if (Z_TYPE_P(res) == IS_OBJECT && ZSTR_VAL((res->value.obj)->ce->name) == obj_class)
        {
            return res;
        }
    }
    return nullptr;
}

zval *read_property(zval *obj, const char *property)
{
    if (Z_TYPE_P(obj) == IS_OBJECT)
    {
        zend_object *object = obj->value.obj;
        zend_class_entry *ce;

        ce = object->ce;

        return zend_read_property(ce, obj, property, strlen(property), 0, nullptr);
    }
    return nullptr;
}

string str_replace_all(string source, string old_str, string new_str)
{
    for (string::size_type pos(0); pos != string::npos; pos += new_str.length())
    {
        if ((pos = source.find(old_str, pos)) != string::npos)
            source.replace(pos, old_str.length(), new_str);
        else
            break;
    }
    return source;
}